﻿#Region "Import"
Imports System.Activities.Core.Presentation
Imports System.Activities.Presentation.View
Imports System.Activities.Presentation
Imports System.Activities.Statements
Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.IO.Path
Imports System.Activities.XamlIntegration
Imports System.Xaml
Imports System.Activities.Core.Presentation.Factories
Imports System.Runtime.InteropServices
Imports System.Activities.Tracking
Imports System.Activities.Debugger
Imports System.Activities.Presentation.Services
Imports System.Activities
Imports System.Windows.Threading
Imports System.Threading
Imports System.Media
Imports System.IO
Imports System.Activities.Presentation.Metadata
Imports System.Reflection

Imports KumaSystem.WFDesignerExpress.TraceSendService
Imports System.Activities.Presentation.Validation
Imports System.Activities.Validation

#End Region

Class MainWindow

#Region "定数定義 Enum"
    Private Enum enmCreateType As Integer
        Sequential = 0
        Flowchart
        Statemachine
        WorkflowService
    End Enum

    Private Const PLUGIN_FOLDERNAME = "Plugin"

    Private Const WFFILE_ARGS As String = "wfile"
    Private Const WFPLUGIN_ARGS As String = "plugin"
    Private Const WFINITIAL_ARGS As String = "init"
#End Region

#Region "変数定義 Variable"
    Private Const all As String = "*"

    Private designer As WorkflowDesigner
    Private debugger As Debug.IDesignerDebugView
    Private customTracker As VisualTrackingParticipant

    Private _tmpFileList As New List(Of String)

    Private _createType As Integer = enmCreateType.Sequential
    Private _editingFilename As String = ""
    Private _executingFilename As String = ""
    Private _firstSaved As Boolean = False

    Private _executingSynclock As New Object
    Private _executing As Boolean = False
    Private _wfApps As WorkflowApplication
    Private _executionWorkflowId As Guid

    Private _traceTextBox As TextBox
    Private _waitTime As String = ""
    Private _trcService As New TraceReceiver

    Private creating As Boolean = True

    Private _pluginfolder As String = ""

    Private _pluginListFilename As String = IO.Path.Combine(My.Settings.CurerntFolder, "liblist.xml")
    Friend _pluginList As New PluginList
#End Region

#Region "プロパティ Property"
    Public Property Executing As Boolean
        Set(ByVal value As Boolean)
            SyncLock _executingSynclock
                _executing = value
                Me.btnExecute.IsEnabled = Not value
                Me.btnPause.IsEnabled = value
            End SyncLock
        End Set
        Get
            Return _executing
        End Get
    End Property
#End Region

#Region "コンストラクタ New-Finalize"
    Public Sub New()
        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()
        ' InitializeComponent() 呼び出しの後で初期化を追加します。

        'トレース受け取り用 WCF サービスを開始
        _trcService.OpenService()
        AddHandler _trcService.TrackingRecordReceived, AddressOf OnTrackingStringsReceived

        Me.EventAdded()
    End Sub

    Private Sub EventAdded()
        AddHandler Me.Loaded, AddressOf WindowLoaded
        AddHandler Me.Closing, AddressOf WindowClosing


        AddHandler chkWallpaper.Click, AddressOf SetWallpaperSettings
    End Sub
#End Region

#Region "ウィンドゥイベント Windows's Event"
    Protected Overrides Sub OnInitialized(ByVal e As System.EventArgs)
        MyBase.OnInitialized(e)

        ' Activities のデザイナーメタデータの登録
        Dim metadata As New DesignerMetadata()
        metadata.Register()

        Dim resDict As New ResourceDictionary With {.Source =
             New Uri("pack://application:,,,/System.Activities.Presentation;V4.0.0.0;31bf3856ad364e35;component/themes/icons.xaml")}
        Me.Resources.MergedDictionaries.Add(resDict)

        'インテリセンスデータの作成または取得
        Tasks.Task.Factory.StartNew(Sub()
                                        Me.CreateIntellisenseList()
                                        creating = False
                                    End Sub)

        Me.Executing = False
    End Sub

    Private Sub WindowLoaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
        'Setting から壁紙設定の復旧
        Dim selectedValue = My.Settings.Wallpaper
        If selectedValue.Trim <> "" Then
            For Each childItem As RibbonGalleryItem In DirectCast(DirectCast(Me.cmbWallpaper.Items(0), RibbonGallery).Items(0), RibbonGalleryCategory).Items
                If childItem.Content = selectedValue Then
                    DirectCast(Me.cmbWallpaper.Items(0), RibbonGallery).SelectedValue = childItem
                    Exit For
                End If
            Next
        End If

        Me.LoadActivities()
        Dim argument = ReplaceArguments(System.Environment.GetCommandLineArgs)
        'ワークフローファイルのチェック
        Dim target = GetWorkflowFilename(argument)
        If target.Trim <> "" Then
            'ワークフローファイルの指定あり
            target = IO.Path.GetFullPath(target)
            CreateNewDesigner(target)
        Else
            Dim initFlow = GetInitializeOption(argument)
            If initFlow <> "" Then
                _createType = ConvertArgumentToWorkflowType(initFlow)
            End If
            CreateNewDesigner("")
        End If

        'Plugin フォルダよりロード
        Dim pluginArg = GetPlugiinFolderOption(argument)
        If pluginArg.Trim = "" Then pluginArg = PLUGIN_FOLDERNAME
        'Plugin 用フォルダに対する設定
        _pluginfolder = Path.Combine(My.Application.Info.DirectoryPath, pluginArg)
        If Not Directory.Exists(_pluginfolder) Then Directory.CreateDirectory(_pluginfolder)
        For Each childDir In Directory.GetDirectories(_pluginfolder, "*", SearchOption.AllDirectories)
            'AppDomain の検索フォルダにプラグインフォルダを指定
            AppDomain.CurrentDomain.AppendPrivatePath(childDir)
        Next
        Me.CheckPluginLibrary(_pluginfolder)

        Dim view = designer.Context.Services.GetService(Of DesignerView)()
        btnUndo.CommandTarget = view
        btnRedo.CommandTarget = view
        btnCopy.CommandTarget = view
        btnPaste.CommandTarget = view
        btnCut.CommandTarget = view
        If My.Settings.Maximized Then Me.WindowState = Windows.WindowState.Maximized
        'Me.chkUseIISExp.IsEnabled = Me.IsIISExpressInstalled

    End Sub

    Private Sub WindowClosing(sender As System.Object, e As System.ComponentModel.CancelEventArgs)
        _trcService.CloseService()

        With My.Settings
            .CurerntFolder = ""
            .UseConsole = Me.chkExecuteOnConsole.IsChecked
            .UsePersist = Me.chkSqlPersist.IsChecked
            If IsNumeric(Me.txtWaitTime.Text) Then
                .WaitTime = Integer.Parse(Me.txtWaitTime.Text)
            Else
                .WaitTime = 0
            End If
            .Height = Me.Height
            .Width = Me.Width
            .WindowX = Me.Left
            .WindowY = Me.Top
            .SplitX = Me.ControlGrid.ActualWidth
            .UseWallpaper = Me.chkWallpaper.IsChecked
            If Me.cmbWallpaper.IsEnabled Then
                .Wallpaper = Me.cmbWallpaper.Text
            Else
                .Wallpaper = ""
            End If
            .UseVoice = False ' Me.chkVoice.IsChecked
            .UseTrace = Me.chkDisplayTrace.IsChecked
            .Maximized = (Me.WindowState = Windows.WindowState.Maximized)
            .ToolBoxFontSize = toolbox.FontSize
        End With
        My.Settings.Save()

        For Each child In _tmpFileList
            Try
                If System.IO.File.Exists(child) Then System.IO.File.Delete(child)
            Catch ex As Exception

            End Try
        Next
    End Sub

    Private Sub GallerySelectionChanged(sender As System.Object, e As System.Windows.RoutedPropertyChangedEventArgs(Of System.Object)) Handles RibbonGallery1.SelectionChanged

        Dim targetGrid = TryCast(DesignerArea.Child, Grid)
        If (targetGrid Is Nothing) OrElse (targetGrid.Children.Count <= 0) Then Return

        For Each childControl In targetGrid.Children
            If (Not TypeOf childControl Is Image) Then Continue For

            Dim gUri = DirectCast(e.NewValue, RibbonGalleryItem).Tag
            If TypeOf gUri Is Uri Then
                Me.SetWallpaper(childControl, gUri)
            Else
                Me.SetWallpaper(childControl, Nothing)
            End If
        Next

    End Sub

    Private Sub SetWallpaperSettings(sender As System.Object, e As System.Windows.RoutedEventArgs)
        Dim targetGrid = TryCast(DesignerArea.Child, Grid)
        If (targetGrid Is Nothing) OrElse (targetGrid.Children.Count <= 0) Then Return
        Dim targetDesigner = targetGrid.Children(1)
        If Me.chkWallpaper.IsChecked Then
            targetDesigner.Opacity = 0.9
        Else
            targetDesigner.Opacity = 1.0
        End If
    End Sub

#Region "ドラッグドロップ Drag and Drop"
    Private Sub DesignerArea_Drop(sender As Object, e As System.Windows.DragEventArgs) Handles DesignerArea.Drop

        If Not e.Data.GetDataPresent(DataFormats.FileDrop) Then Return

        Dim dropItem() As String = e.Data.GetData(DataFormats.FileDrop)
        If (dropItem Is Nothing) OrElse (dropItem.Length <= 0) Then Return

        If MessageBox.Show(Me.GetResourceStrings("MsgDropItemLoad", "新しくワークフローを読み込みますか？"),
                           My.Application.Info.Title,
                           MessageBoxButton.YesNo,
                           MessageBoxImage.Question,
                           MessageBoxResult.No) = MessageBoxResult.No Then Return

        CreateNewDesigner(dropItem(0))

    End Sub
#End Region

#End Region

#Region "ツールボックス・デザイナ Toolbox/Designer"
    ''' <summary>ツールボックスへのアクティビティ読み込み</summary>
    Private Sub LoadActivities()

        Me.Cursor = Cursors.Wait

        'Workflow4 Activities
        With DirectCast(ToolboxArea.Child, Toolbox.ToolboxControl)

            '.Categories.Add(New Toolbox.ToolboxCategory("TEST"))
            'With .Categories(.Categories.Count - 1)
            '    .Add(CreateToolboxItemWrapper(GetType(Activities.FileSystem.FileCopyActivity), "FileCopy"))
            'End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatControlFlow", "フロー制御")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(ForEachWithBodyFactory(Of String)), "ForEach"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.If), "If"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Parallel), "Parallel"))
                .Add(CreateToolboxItemWrapper(GetType(ParallelForEachWithBodyFactory(Of String)), "ParallelForEach"))
                .Add(CreateToolboxItemWrapper(GetType(PickWithTwoBranchesFactory), "Pick"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.PickBranch), "PickBranch"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Sequence), "Sequence"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Switch(Of String)), "Switch"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.While), "While"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.DoWhile), "DoWhile"))
            End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatFlowchart", "フローチャート")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Flowchart), "Flowchart"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.FlowDecision), "FlowDecision"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.FlowSwitch(Of String)), "FlowSwitch"))
            End With

            'Statemachine Activities is WF 4.5  (Older : Platform Update 1)
            '.Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatStatemachine", "ステートマシン")))
            'With .Categories(.Categories.Count - 1)
            '    '    .Add(CreateToolboxItemWrapper(GetType(System.Activities.Core.Presentation.Factories.StateMachineWithInitialStateFactory), "StateMachine"))
            '    '    .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.State), "State"))
            '    '    .Add(CreateToolboxItemWrapper(GetType(System.Activities.Core.Presentation.FinalState), "Final State"))

            '    .Add(CreateToolboxItemWrapper(GetType(Microsoft.Activities.Statements.Design.ToolboxItems.StateMachineWithInitialStateFactory), "StateMachine"))
            '    .Add(CreateToolboxItemWrapper(GetType(Microsoft.Activities.Statements.State), "State"))
            '    .Add(CreateToolboxItemWrapper(GetType(Microsoft.Activities.Statements.Design.ToolboxItems.FinalState), "FinalState"))
            'End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatMessaging", "メッセージング")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.CorrelationScope), "CorrelationScope"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.InitializeCorrelation), "InitializeCorrelation"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.Receive), "Receive"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.ReceiveReply), "ReceiveReply"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.Presentation.Factories.ReceiveAndSendReplyFactory), "ReceiveAndSendReply"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.Send), "Send"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.SendReply), "SendReply"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.Presentation.Factories.SendAndReceiveReplyFactory), "SendAndReceiveReply"))
                .Add(CreateToolboxItemWrapper(GetType(System.ServiceModel.Activities.TransactedReceiveScope), ""))
            End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatRuntime", "ランタイム")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Persist), "Persist"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.TerminateWorkflow), "TerminateWorkflow"))
            End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatPrimitives", "プリミティブ")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Assign), "Assign"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Delay), "Delay"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.InvokeMethod), "InvokeMethod"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.WriteLine), "WriteLine"))
            End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatTransaction", "トランザクション")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.CancellationScope), "CancellationScope"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.CompensableActivity), "CompensableActivity"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Compensate), "Compensate"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Confirm), "Confirm"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.TransactionScope), "TransactionScope"))
            End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatCollection", "コレクション")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.AddToCollection(Of String)), "AddToCollection"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.ClearCollection(Of String)), "ClearCollection"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.ExistsInCollection(Of String)), "ExistsInCollection"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.RemoveFromCollection(Of String)), "RemoveFromCollection"))
            End With

            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatErrorhandling", "エラー処理")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Rethrow), "Rethrow"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Throw), "Throw"))
                .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.TryCatch), "TryCatch"))
            End With

            'Interop Activity can't use Client Profile
            '.Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatInterop", "移行")))
            'With .Categories(.Categories.Count - 1)
            '    .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.Interop), "Interop"))
            'End With

            'Activities WF 4.5 
            '.Categories.Add(New Toolbox.ToolboxCategory("WF 4.5"))
            'With .Categories(.Categories.Count - 1)
            '    .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.InvokeDelegate), "InvokeDelegate"))
            '    .Add(CreateToolboxItemWrapper(GetType(System.Activities.Statements.NoPersistScope), "NoPersistScope"))
            'End With

            '独自追加アクティビティ : Original Activity
            .Categories.Add(New Toolbox.ToolboxCategory(Me.GetResourceStrings("CatAddin", "アドイン")))
            With .Categories(.Categories.Count - 1)
                .Add(CreateToolboxItemWrapper(GetType(BookmarkActivity), "BookmarkActivity"))
                .Add(CreateToolboxItemWrapper(GetType(ReadKeyActivity), "ReadKeyActivity"))
                .Add(CreateToolboxItemWrapper(GetType(CommentOutActivity), "CommentOutActivity"))
                .Add(CreateToolboxItemWrapper(GetType(MessageBoxActivity), "MessageBoxActivity"))
                .Add(CreateToolboxItemWrapper(GetType(ZipCompressActivity), "ZipCompressActivity"))

                .Add(CreateToolboxItemWrapper(GetType(AsyncTaskActivity), "AsyncTaskActivity"))
            End With
        End With

        'アドインアクティビティのメタデータ登録
        Dim selfTypes() As Type = {GetType(BookmarkActivity), GetType(ReadKeyActivity),
                                               GetType(CommentOutActivity), GetType(MessageBoxActivity),
                                               GetType(ZipCompressActivity), GetType(AsyncTaskActivity)}
        For Each childMeta In selfTypes
            Dim metadata = TryCast(Activator.CreateInstance(childMeta), Metadata.IRegisterMetadata)
            If metadata IsNot Nothing Then metadata.Register()
        Next

        Me.Cursor = Cursors.Arrow

    End Sub

    ''' <summary>ツールボックス登録用ラッパークラス生成</summary>
    Private Function CreateToolboxItemWrapper(ByVal targetType As System.Type, ByVal dispName As String) As Toolbox.ToolboxItemWrapper
        If dispName.Trim = "" Then
            If targetType.IsGenericType Then
                dispName = targetType.GetGenericTypeDefinition.Name
            Else
                If targetType.Name.Contains("TransactedReceiveScope") Then
                    dispName = "TransactionReceiveScope"
                Else
                    dispName = targetType.Name
                End If
            End If
        End If

        Dim result  = New Toolbox.ToolboxItemWrapper(targetType, dispName)
        Return result
    End Function

    ''' <summary>新規にデザイナを生成</summary>
    Private Sub CreateNewDesigner(ByVal targetFilename As String)
        ' ワークフローデザイナーの作成
        Me.Cursor = Cursors.Wait
        DispatcherHelper.DoEvents()

        If designer IsNot Nothing Then
            Dim content = TryCast(DesignerArea.Child, Grid)
            If content IsNot Nothing Then
                If content.Children.Contains(designer.View) Then content.Children.Remove(designer.View)
            End If
        End If

        'インテリセンスデータが生成されるまで待機
        Do While creating
            System.Threading.Thread.Sleep(1)
        Loop

        designer = New WorkflowDesigner()
        debugger = designer.DebugManagerView
        Dim expEditor As New EditorService() With {
            .IntellisenseData = _inttelisenseList,
            .EditorKeyWord = Me.CreateKeywords
        }
        designer.Context.Services.Publish(Of IExpressionEditorService)(expEditor)

        Dim wfActivities As Object = Nothing
        Dim activityBuilderType As New ActivityBuilder
        _firstSaved = False
        If String.IsNullOrEmpty(targetFilename) Then
            ' アクティビティを挿入しておく
            Select Case _createType
                Case enmCreateType.Sequential
                    wfActivities = New Sequence
                    activityBuilderType.Name = "Sequence"
                    _editingFilename = "sequence.xaml"
                Case enmCreateType.Flowchart
                    wfActivities = New Flowchart
                    activityBuilderType.Name = "Flowchart"
                    _editingFilename = "flowchart.xaml"

                Case enmCreateType.Statemachine
                    wfActivities = Me.CreateStatemachineActivity
                    activityBuilderType.Name = "StateMachine"
                    _editingFilename = "stateMachine.xaml"

                Case enmCreateType.WorkflowService
                    designer.Load(New System.ServiceModel.Activities.WorkflowService With {.ConfigurationName = "Service1", .Name = "Service1"})
                    _editingFilename = "workflowService.xaml"
            End Select
        Else
            'ファイル名を指定して Load しないと SourceLocationProvider.CollectMapping が動作しない
            '[SourceLocationProvider.CollectMapping] need [WorkflowDesigner.Load(Filename)]
            designer.Load(targetFilename)
            _firstSaved = True
            _editingFilename = targetFilename
        End If
        If wfActivities IsNot Nothing Then
            activityBuilderType.Implementation = wfActivities
            designer.Load(activityBuilderType)
        End If

        Dim titleStrings = My.Application.Info.Title + "[" + _editingFilename + "]"
        If Not _firstSaved Then titleStrings += "*"
        Me.Title = titleStrings

        ' UIElement (デザイナービュー、プロパティビュー) の挿入
        Dim designView = designer.View
        Dim contentGrid = New Grid
        Dim designImage = New Image

        If chkWallpaper.IsChecked Then
            designView.Opacity = 0.9
        Else
            designView.Opacity = 1.0
        End If

        Dim gUri = Me.GetSelectedWallpaperUri()
        If gUri IsNot Nothing Then Me.SetWallpaper(designImage, gUri)

        contentGrid.Children.Add(designImage)
        contentGrid.Children.Add(designView)
        DesignerArea.Child = contentGrid

        Dim wfProperty = designer.PropertyInspectorView
        PropertyArea.Child = wfProperty
        Me.AddTrackingTextBox()

        Me.AddContextMenu()

        Me.Cursor = Cursors.Arrow

    End Sub

    ''' <summary>リボンコンボボックスにて選択されている壁紙のUriを取得</summary>
    Private Function GetSelectedWallpaperUri() As Uri
        Dim selectedValue = DirectCast(DirectCast(Me.cmbWallpaper.Items(0), RibbonGallery).SelectedValue, RibbonGalleryItem)
        If (selectedValue Is Nothing) OrElse (Not TypeOf selectedValue.Tag Is Uri) Then Return Nothing
        Return selectedValue.Tag
    End Function

    ''' <summary>Imageコントロールに壁紙を設定</summary>
    Private Sub SetWallpaper(ByVal targetControl As Image, ByVal gUri As Uri)
        If (gUri Is Nothing) Then
            targetControl.Source = Nothing
        Else
            targetControl.Source = New BitmapImage(gUri)
        End If
        targetControl.Stretch = Stretch.Uniform
        targetControl.HorizontalAlignment = Windows.HorizontalAlignment.Right
        targetControl.FlowDirection = Windows.FlowDirection.RightToLeft
    End Sub

    ''' <summary>Statemachine 関係のライブラリが参照され利用可能かどうか</summary>
    Private Function CanUseStatemachine() As Boolean
        Return (AppDomain.CurrentDomain.GetAssemblies.Where(Function(asm)
                                                                Return asm.GetName.Name.ToLower.Contains("statemachine")
                                                            End Function).Count > 0)
    End Function

    Private Const STATEMACHINEBASE41 = "System.Activities.Core.Presentation.Factories.StateMachineWithInitialStateFactory"
    Private Const STATEMACHINEBASECP = "Microsoft.Activities.Statements.Design.ToolboxItems.StateMachineWithInitialStateFactory"

    Private Const STATEMACHINE41 = "System.Activities.Statements.StateMachine"
    Private Const STATEMACHINECP = "Microsoft.Activities.Statements.StateMachine"

    ''' <summary>Statemachine アクティビティの新規作成</summary>
    Private Function CreateStatemachineActivity() As Object
        Dim result As Object = Nothing
        For Each childAsm In AppDomain.CurrentDomain.GetAssemblies.Where(Function(asm)
                                                                             Return asm.GetName.Name.ToLower.Contains("statemachine")
                                                                         End Function)

            Dim stmType = childAsm.GetType(STATEMACHINE41)
            If stmType Is Nothing Then stmType = childAsm.GetType(STATEMACHINECP)
            If stmType Is Nothing Then Continue For

            result = Activator.CreateInstance(stmType)
            Exit For
        Next
        Return result
    End Function

#End Region

#Region "ツールバーボタン Toolbar"
    '''<summary>終了ボタン</summary>
    Private Sub QuitApplication(sender As System.Object, e As System.Windows.RoutedEventArgs)
        My.Application.Shutdown()
    End Sub

    '''<summary>ワークフローの保存ボタン</summary>
    Private Sub SaveWorkflow(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'If designer.IsInErrorState Then
        '    MessageBox.Show(Me.GetResourceStrings("MsgCheckExceptionInFlow", "ワークフロー中にエラーがあります。"),
        '                              My.Application.Info.Title,
        '                              MessageBoxButton.OK, MessageBoxImage.Warning)
        '    Return
        'End If

        'ワークフローの保存
        Dim dlg As New Microsoft.Win32.SaveFileDialog
        With dlg
            .AddExtension = True
            .CheckFileExists = False
            .Filter = Me.GetResourceStrings("MsgOpenWorkflowFilter",
                                            "ワークフロー(*.xaml)|*.xaml|ワークフローサービス(*.xamlx) |*.xamlx|全てのファイル(*.*)|*.*")
            .FileName = System.IO.Path.GetFileNameWithoutExtension(_editingFilename)
            .InitialDirectory = System.IO.Path.GetDirectoryName(_editingFilename)
        End With
        If dlg.ShowDialog Then
            Me.Cursor = Cursors.Wait
            DispatcherHelper.DoEvents()

            designer.Flush()
            Try
                Dim mdlTree = designer.Context.Services.GetService(Of Model.ModelTreeManager).Root
                Dim sb As New System.Text.StringBuilder
                Dim xsc As XamlSchemaContext = Nothing
                If _addLibrary.Count <= 0 Then
                    xsc = New XamlSchemaContext
                Else
                    xsc = New XamlSchemaContext(_addLibrary)
                End If
                Dim bw = ActivityXamlServices.CreateBuilderWriter(New IgnorableXamlXmlWriter(New System.IO.StringWriter(sb), xsc))

                XamlServices.Save(bw, mdlTree.GetCurrentValue)
                My.Computer.FileSystem.WriteAllText(dlg.FileName, sb.ToString, False)
                'designer.Save(dlg.FileName)
            Catch ex As Exception

            Finally
                ''Igonorable属性を付与したものを再ロード
                'CreateNewDesigner(dlg.FileName)
                _editingFilename = dlg.FileName
                Dim titleStrings = My.Application.Info.Title + "[" + System.IO.Path.GetFileName(_editingFilename) + "]"
                Me.Title = titleStrings

                Me.Cursor = Cursors.Arrow
            End Try
        End If
    End Sub

    '''<summary>ワークフローの読み込みボタン</summary>
    Private Sub OpenWorkflow(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'ワークフローの読み込み
        Dim dlg As New Microsoft.Win32.OpenFileDialog
        With dlg
            .AddExtension = True
            .CheckFileExists = True
            .Filter = Me.GetResourceStrings("MsgOpenWorkflowFilter",
                                            "ワークフロー(*.xaml)|*.xaml|ワークフローサービス(*.xamlx) |*.xamlx|全てのファイル(*.*)|*.*")
        End With
        If dlg.ShowDialog Then
            CreateNewDesigner(dlg.FileName)
        End If
    End Sub

    '''<summary>新規作成ボタン</summary>
    Private Sub CreateNewWorkflowClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Select Case DirectCast(sender, Control).Name
            Case mnuNewSequence.Name, mniNewSequence.Name
                _createType = enmCreateType.Sequential
            Case mnuNewFlwochart.Name, mniNewFlowchart.Name
                _createType = enmCreateType.Flowchart
            Case mnuNewStatemachine.Name, mniNewStateMachine.Name
                _createType = enmCreateType.Statemachine
            Case Else
                _createType = enmCreateType.WorkflowService
        End Select
        CreateNewDesigner("")
    End Sub

    ''' <summary>ワークフローの実行</summary>
    Private Sub ExecuteWorkflow(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

        Dim errID = Me.ValidateActivities()
        If (errID <> "") OrElse (designer.IsInErrorState) Then
            MessageBox.Show(Me.GetResourceStrings("MsgCheckExceptionInFlow", "ワークフロー中にエラーがあります。"),
                                      My.Application.Info.Title,
                                      MessageBoxButton.OK, MessageBoxImage.Warning)
            If errID <> "" Then
                Dim vsv = designer.Context.Services.GetService(Of ValidationService)()
                vsv.NavigateToError(errID)
            End If
            Return
        End If

        Me.Cursor = Cursors.Wait
        Me.Executing = True
        _traceTextBox.Clear()

        '現状を一度仮保存する
        designer.Flush()
        Dim tmpName = My.Computer.FileSystem.GetTempFileName
        Try
            Dim mdlTree = designer.Context.Services.GetService(Of Model.ModelTreeManager).Root
            Dim sb As New System.Text.StringBuilder
            Dim xsc As XamlSchemaContext = Nothing
            If _addLibrary.Count <= 0 Then
                xsc = New XamlSchemaContext
            Else
                xsc = New XamlSchemaContext(_addLibrary)
            End If
            Dim bw = ActivityXamlServices.CreateBuilderWriter(New IgnorableXamlXmlWriter(New System.IO.StringWriter(sb), xsc))

            XamlServices.Save(bw, mdlTree.GetCurrentValue)
            My.Computer.FileSystem.WriteAllText(tmpName, sb.ToString, False)
            _tmpFileList.Add(tmpName)
            _executingFilename = tmpName
        Catch ex As NullReferenceException
        Catch ex As Exception
            MessageBox.Show(ex.Message,
                                      My.Application.Info.Title,
                                      MessageBoxButton.OK, MessageBoxImage.Warning)
            Me.Executing = False
            Return
        End Try

        Dim persistInstance As DurableInstancing.SqlWorkflowInstanceStore = Me.CreatePersistance

        If chkExecuteOnConsole.IsChecked Then
            'コンソールアプリケーションとして実行
            Me.PlayVoice(WorkflowEventEnum.Start)
            Dim consoleArgument = "/wfile:" + ControlChars.Quote + tmpName + ControlChars.Quote +
                                               " /wait:true /plugin:" + ControlChars.Quote + _pluginfolder + ControlChars.Quote
            If Me.chkDisplayTrace.IsChecked Then consoleArgument += " /usetrace:true"
            Dim conExec = System.Diagnostics.Process.Start("ConsoleExecuter.exe", consoleArgument)
            conExec.WaitForExit()
            Me.Executing = False
        Else
            'Winアプリケーションとして実行
            Try
                Me.Cursor = Cursors.Arrow

                'アクティビティの適用
                Dim wfFile = ActivityXamlServices.Load(tmpName)
                WorkflowInspectionServices.CacheMetadata(wfFile)
                _trcService.SrcDict = GetSourceLocationMap(wfFile, tmpName)
                _trcService.ActivityIdDict = _trcService.GetIdActivityMap()

                _wfApps = New WorkflowApplication(wfFile) ', wfArgs)
                _wfApps.SynchronizationContext = SynchronizationContext.Current
                If persistInstance IsNot Nothing Then
                    _wfApps.InstanceStore = persistInstance
                End If
                _wfApps.Completed = AddressOf Completed
                _wfApps.Aborted = AddressOf Aboted
                _wfApps.OnUnhandledException = AddressOf OnUnhandledException
                _wfApps.PersistableIdle = AddressOf PersistableIdle
                '_wfApps.Unloaded = AddressOf WfUnloaded

                'トラッキングプロファイルの生成
                If Me.chkDisplayTrace.IsChecked Then
                    customTracker = New VisualTrackingParticipant
                    customTracker.TrackingProfile = _trcService.CreateTrackingProfile()
                    customTracker.ActivityIdToWorkflowElementMap = _trcService.ActivityIdDict
                    'customTracker.ActivityElementMap = mdlDict
                    'トラッキングレコード受信時のイベントトラップ
                    AddHandler customTracker.TrackingRecordReceived, AddressOf OnTrackingRecordReceived
                    _wfApps.Extensions.Add(customTracker)
                End If

                _useVoice = False 'Me.chkVoice.IsChecked
                _waitTime = Me.txtWaitTime.Text
                Me.PlayVoice(WorkflowEventEnum.Start)
                _wfApps.Run()
                _executionWorkflowId = _wfApps.Id
            Catch ex As Exception
                MessageBox.Show(ex.Message,
                              My.Application.Info.Title,
                              MessageBoxButton.OK, MessageBoxImage.Warning)
                Me.Executing = False
            Finally
                '_wfApps = Nothing
            End Try
        End If


    End Sub

    '''<summary>ワークフローの停止ボタン</summary>
    Private Sub PauseWorkflow(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If _wfApps Is Nothing Then Return
        _wfApps.Cancel()
    End Sub

    '''<summary>XAML表示</summary>
    Private Sub ViewWorkflowXaml(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim dlg As New XamlViewDialog With {.Owner = Me}
        designer.Flush()
        dlg.XamlText = designer.Text
        dlg.ShowDialog()
    End Sub

    ''' <summary>永続化設定ダイアログの表示ボタン</summary>
    Private Sub SettingPersistant(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

        Dim dlg As New PersistSettingDialog With {.Owner = Me}

        dlg.ShowDialog()

    End Sub

    ''' <summary>SQL Server 永続化設定の作成</summary>
    Private Function CreatePersistance() As DurableInstancing.SqlWorkflowInstanceStore
        Dim result As DurableInstancing.SqlWorkflowInstanceStore = Nothing
        If chkSqlPersist.IsChecked Then
            'SQL Server の永続化を有効にする
            Dim conBuild As New System.Data.SqlClient.SqlConnectionStringBuilder
            conBuild.DataSource = My.Settings.PersistInstance
            conBuild.InitialCatalog = My.Settings.PersistCatalog
            conBuild.IntegratedSecurity = My.Settings.PersistUseWindowsAuth
            If Not My.Settings.PersistUseWindowsAuth Then
                conBuild.UserID = My.Settings.PersistAccount
                conBuild.Password = My.Settings.PersistPassword
            End If
            result = New DurableInstancing.SqlWorkflowInstanceStore(conBuild.ToString)
        End If
        Return result
    End Function

    ''' <summary>外部ファイルの参照追加</summary>
    Private Sub AddLibrary(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        'Return

        Dim dlg As New Microsoft.Win32.OpenFileDialog
        With dlg
            .AddExtension = True
            .CheckFileExists = True
            .Multiselect = False
            .Filter = Me.GetResourceStrings("MsgOpenAddinFilter",
                                                         "リンクライブラリ(*.dll)|*.dll|全てのファイル(*.*)|*.*")
        End With
        If Not dlg.ShowDialog Then Return

        Dim targetLibFilename = Path.GetFileNameWithoutExtension(dlg.SafeFileName)
        Dim newPluginFolder = Path.Combine(_pluginfolder, targetLibFilename)
        CopyFromPluginFolder(Path.GetDirectoryName(dlg.FileName), newPluginFolder)

        Me.LoadActivities(newPluginFolder)
        Dim addCategory = New Toolbox.ToolboxCategory(targetLibFilename)
        For Each childAsm In Directory.GetFiles(newPluginFolder, "*.dll", SearchOption.TopDirectoryOnly)
            Dim targetAsm = Reflection.Assembly.LoadFrom(Path.Combine(newPluginFolder, Path.GetFileName(childAsm)))
            Me.AddActivities(targetAsm, addCategory, targetLibFilename)
        Next

        Dim stmEnabled = Me.CanUseStatemachine()
        mniNewStateMachine.IsEnabled = stmEnabled
        mnuNewStatemachine.IsEnabled = stmEnabled

    End Sub

    ''' <summary>ツールボックスのフォントサイズ調整</summary>
    Private Sub UIFontSizeChange(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If DirectCast(sender, RibbonButton).Name = btnUpSize.Name Then
            'サイズの拡大
            toolbox.FontSize += 1
        Else
            'サイズの縮小
            toolbox.FontSize -= 1
        End If
    End Sub

    ''' <summary>ワークフローの検証を行う</summary>
    Private Function ValidateActivities() As String
        Dim resultID As String = ""

        designer.Flush()
        Dim vsv = designer.Context.Services.GetService(Of ValidationService)()
        Dim rootActivity = GetDebugActivity()
        Dim validError = ActivityValidationServices.Validate(rootActivity)
        If validError.Errors.Count > 0 Then resultID = validError.Errors(validError.Errors.Count - 1).Id

        Return resultID
    End Function

#End Region

#Region "ワークフロー実行イベント Executing Workflow's Event"
    Private Sub Completed(ByVal e As WorkflowApplicationCompletedEventArgs)
        Me.PlayVoice(WorkflowEventEnum.Complete)

        MessageBox.Show(Me.GetResourceStrings("MsgComplete", "ワークフローの実行が終了しました。"),
                                  My.Application.Info.Title,
                                  MessageBoxButton.OK, MessageBoxImage.Information)
        designer.DebugManagerView.CurrentLocation = Nothing
        If Me.CheckAccess Then
            Me.Executing = False
        Else
            Dispatcher.BeginInvoke(New Action(Of Boolean)(AddressOf SetExecutingProperty), False)
        End If
    End Sub

    Private Sub Aboted(ByVal e As WorkflowApplicationAbortedEventArgs)
        Me.PlayVoice(WorkflowEventEnum.Abort)

        MessageBox.Show(Me.GetResourceStrings("MsgAbort", "ワークフローの実行を中止しました。"),
                                  My.Application.Info.Title,
                                  MessageBoxButton.OK, MessageBoxImage.Information)
        designer.DebugManagerView.CurrentLocation = Nothing
        If Me.CheckAccess Then
            Me.Executing = False
        Else
            Dispatcher.BeginInvoke(New Action(Of Boolean)(AddressOf SetExecutingProperty), False)
        End If
    End Sub

    Private Function OnUnhandledException(ByVal e As WorkflowApplicationUnhandledExceptionEventArgs)
        Me.PlayVoice(WorkflowEventEnum.UnHandledException)
        Dim errMsg As New System.Text.StringBuilder

        MessageBox.Show(Me.GetResourceStrings("MsgUnhandled", "ワークフローの実行中にエラーが発生しました。"),
                                  My.Application.Info.Title,
                                  MessageBoxButton.OK, MessageBoxImage.Information)
        designer.DebugManagerView.CurrentLocation = Nothing
        If Me.CheckAccess Then
            Me.Executing = False
        Else
            Dispatcher.BeginInvoke(New Action(Of Boolean)(AddressOf SetExecutingProperty), False)
        End If
        Return e
    End Function

    Private Function PersistableIdle(ByVal e As WorkflowApplicationIdleEventArgs) As PersistableIdleAction
        Return PersistableIdleAction.Persist
    End Function

    'Private instanceUnloaded As New AutoResetEvent(False)
    'Private Sub WfUnloaded(ByVal e As WorkflowApplicationEventArgs)
    '    instanceUnloaded.Set()
    'End Sub

    Private Sub SetExecutingProperty(ByVal value As Boolean)
        Me.Executing = value
    End Sub

    Private Enum WorkflowEventEnum As Integer
        Start = 0
        Complete
        Abort
        UnHandledException
    End Enum

    Private _useVoice As Boolean = False
    Private Sub PlayVoice(ByVal mode As WorkflowEventEnum)
        If Not _useVoice Then Return

        Dim sndFileName = ""
        Select Case mode
            Case WorkflowEventEnum.Start '01,30
                Dim sv = (New Random(Now.Second)).Next(2)
                If sv = 0 Then
                    sndFileName = "01sahajimeru.wav"
                Else
                    sndFileName = "30start.wav"
                End If
            Case WorkflowEventEnum.Complete '03,16,35
                Dim sv = (New Random(Now.Second)).Next(3)
                Select Case sv
                    Case 0 : sndFileName = "03syuuryou.wav"
                    Case 1 : sndFileName = "16finiiish.wav"
                    Case 2 : sndFileName = "35daiseikou.wav"
                End Select
            Case WorkflowEventEnum.Abort '40
                sndFileName = "40chui.wav"
            Case WorkflowEventEnum.UnHandledException '34,37
                Dim sv = (New Random(Now.Second)).Next(2)
                If sv = 0 Then
                    sndFileName = "34sippai.wav"
                Else
                    sndFileName = "37ah.wav"
                End If

        End Select
        sndFileName = ".\images\cloudia\voice\" + sndFileName
        Try
            My.Computer.Audio.Play(sndFileName, AudioPlayMode.Background)
        Catch ex As Exception

        End Try
    End Sub
#End Region

#Region "デバッグ時トレース Debug Trace"

    Private Sub AddTrackingTextBox()
        _traceTextBox = New TextBox
        If TraceArea.Child IsNot Nothing Then
            TraceArea.Child = Nothing
        End If
        TraceArea.Child = _traceTextBox

        AddHandler _traceTextBox.SelectionChanged, AddressOf traceTextBoxSelectionChanged
    End Sub

    Private Sub traceTextBoxSelectionChanged(sender As Object, e As RoutedEventArgs)

        Dim text As String = _traceTextBox.Text

        Dim index As Integer = 0
        Dim lineClicked As Integer = 0
        While index < text.Length
            If text(index) = ControlChars.Lf Then
                lineClicked += 1
            End If
            If _traceTextBox.SelectionStart <= index Then
                Exit While
            End If

            index += 1
        End While

    End Sub

    Private Sub ShowDebug(ByVal srcLoc As SourceLocation)
        Me.Dispatcher.Invoke(DispatcherPriority.Render,
                                       DirectCast(Sub()
                                                      designer.DebugManagerView.CurrentLocation = srcLoc
                                                  End Sub, Action))

    End Sub

    Private Sub OnTrackingStringsReceived(ByVal sender As String)
        Dim waitTime As Integer = TraceReceiver.VISUALTRACE_WAITTIME
        If (_waitTime.Trim <> "") Then
            Integer.TryParse(_waitTime, waitTime)
        End If
        Me.Dispatcher.Invoke(DispatcherPriority.SystemIdle,
                               DirectCast(Function()
                                              _traceTextBox.AppendText(sender)
                                              'System.Threading.Thread.Sleep(waitTime)
                                              Return Nothing
                                          End Function, Action))
    End Sub

    Private Function OnTrackingRecordReceived(ByVal sender As System.Activities.Tracking.TrackingParticipant, ByVal e As TrackingEventArgs)

        Dim trackRecord = TryCast(e.Record, ActivityStateRecord)
        If trackRecord Is Nothing Then Return Nothing
        If _trcService.ActivityIdDict.ContainsKey(trackRecord.Activity.Id) Then
            Dim targetActivity = _trcService.ActivityIdDict(trackRecord.Activity.Id)
            ShowDebug(_trcService.SrcDict(targetActivity))
        End If

        Dim waitTime As Integer = TraceReceiver.VISUALTRACE_WAITTIME
        If (_waitTime.Trim <> "") Then
            Integer.TryParse(_waitTime, waitTime)
        End If
        Me.Dispatcher.Invoke(DispatcherPriority.SystemIdle,
                               DirectCast(Function()
                                              _traceTextBox.AppendText(trackRecord.Activity.Name + " " _
                                                                                + trackRecord.State + ControlChars.NewLine)
                                              _traceTextBox.AppendText("--------------------------" + ControlChars.NewLine)

                                              System.Threading.Thread.Sleep(waitTime)

                                              Return Nothing
                                          End Function, Action))
        Return Nothing

    End Function

    Private Function GetSourceLocationMap(ByVal root As activity, ByVal loadFile As String) As Dictionary(Of Object, SourceLocation)
        Dim runtime_debug = New Dictionary(Of Object, SourceLocation)
        Dim debug_debug = New Dictionary(Of Object, SourceLocation)

        Dim debugActivity = GetDebugActivity()
        Dim runtimeActivity = GetRuntimeActivity(root)
        SourceLocationProvider.CollectMapping(runtimeActivity, debugActivity,
                                                              runtime_debug, loadFile)
        SourceLocationProvider.CollectMapping(debugActivity, debugActivity,
                                                              debug_debug, loadFile)
        DirectCast(designer.DebugManagerView, Debug.DebuggerService).UpdateSourceLocations(debug_debug)
        Return runtime_debug
    End Function

    Public Function GetDebugActivity() As Activity
        Dim mdlService = designer.Context.Services.GetService(Of ModelService)()
        Dim debugTree = TryCast(mdlService.Root.GetCurrentValue(), IDebuggableWorkflowTree)
        If (debugTree IsNot Nothing) Then
            Return debugTree.GetWorkflowRoot()
        Else
            'Return DirectCast(mdlService.Root, System.Activities.Presentation.Model.ModelItemImpl)
            Return mdlService.Root.GetCurrentValue()
        End If

    End Function

    Public Function GetRuntimeActivity(ByVal root As activity) As Activity
        Dim list = WorkflowInspectionServices.GetActivities(root).GetEnumerator()
        list.MoveNext()
        Return list.Current
    End Function

#End Region

#Region "外部アクティビティ読み込み External Library Addin"

    Private _addLibrary As New List(Of Reflection.Assembly)

    ''' <summary>Plugin Activity をプラグイン用フォルダにコピーする</summary>
    Private Sub CopyFromPluginFolder(ByVal originalFolder As String, ByVal pluginFolder As String)
        If originalFolder.Equals(pluginFolder) Then Return
        Try
            My.Computer.FileSystem.CopyDirectory(originalFolder,
                                                 pluginFolder, True)
        Catch ex As Exception
            MessageBox.Show(ex.Message, My.Application.Info.Title,
                                      MessageBoxButton.OK, MessageBoxImage.Warning)
            Return
        End Try
    End Sub

    ''' <summary>Activity をロードしツールボックスに追加する</summary>
    Private Sub AddActivities(ByVal targetAsm As Reflection.Assembly, ByVal addCategory As Toolbox.ToolboxCategory, ByVal targetLibFilename As String)
        With DirectCast(ToolboxArea.Child, Toolbox.ToolboxControl)
            If Not .Categories.Contains(addCategory) Then .Categories.Add(addCategory)

            For catIndex As Integer = 0 To .Categories.Count - 1
                If Not .Categories(catIndex).CategoryName = targetLibFilename Then Continue For

                For Each child In targetAsm.GetTypes().Where(Function(t)
                                                                 Return (IsStatemachineActivity(t) OrElse
                                                                            GetType(Activity).IsAssignableFrom(t) OrElse
                                                                            GetType(IActivityTemplateFactory).IsAssignableFrom(t)) AndAlso
                                                                     Not t.IsAbstract AndAlso t.IsVisible
                                                             End Function)
                    Dim activityName = child.Name
                    If activityName.Contains("`") Then
                        activityName = activityName.Substring(0, activityName.LastIndexOf("`"))
                    End If
                    Dim addItem = Me.CreateToolboxItemWrapper(child, activityName)
                    If Not .Categories(catIndex).Tools.Contains(addItem) Then
                        .Categories(catIndex).Add(addItem)
                    End If
                Next

                Exit For

            Next
        End With
    End Sub

    ''' <summary>Plugin フォルダに存在する DLL を全てロードし、リソースを抽出する</summary>
    Private Function LoadActivities(ByVal newPluginFolder As String) As List(Of String)
        Dim resultAsms As New List(Of String)
        If ToolboxIconExtraction.iconsDict Is Nothing Then ToolboxIconExtraction.CreateInitialResource()

        'Plugin フォルダに存在する DLL を全てロード
        For Each childDll In Directory.GetFiles(newPluginFolder, "*.dll", SearchOption.TopDirectoryOnly)
            Dim childAsm = Reflection.Assembly.LoadFrom(childDll)
            resultAsms.Add(childDll)

            'IRegisterMetadata.Register を呼ぶ
            Dim meta = childAsm.GetTypes().Where(Function(t)
                                                     Dim tp = GetType(Metadata.IRegisterMetadata)
                                                     Return tp.IsAssignableFrom(t) AndAlso Not t.IsAbstract AndAlso t.IsVisible
                                                 End Function)
            Dim validReference As Boolean = False
            Tasks.Parallel.ForEach(meta, Sub(childMeta)
                                             Dim metadata = TryCast(Activator.CreateInstance(childMeta), Metadata.IRegisterMetadata)
                                             If metadata IsNot Nothing Then
                                                 metadata.Register()
                                                 validReference = True
                                             End If
                                         End Sub)

            'ActivityDesigner からアイコンを抽出する
            Dim actDes = childAsm.GetTypes().Where(Function(t)
                                                       Return GetType(ActivityDesigner).IsAssignableFrom(t) AndAlso Not t.IsAbstract AndAlso t.IsVisible
                                                   End Function)
            For Each childAct In actDes
                Dim childDes As ActivityDesigner = Nothing
                Try
                    childDes = TryCast(Activator.CreateInstance(childAct), ActivityDesigner)
                    If childDes Is Nothing Then Continue For
                Catch ex As Exception
                    Continue For
                End Try
                Dim targetActivityName = childAct.Name
                If (targetActivityName.Contains("Designer")) Then targetActivityName = targetActivityName.Replace("Designer", "")

                Dim resourceKey = ToolboxIconExtraction.GetResourceName(targetActivityName)
                Dim icoRes As DrawingBrush = Nothing
                If childDes.Icon IsNot Nothing AndAlso childDes.Icon.Drawing IsNot Nothing Then
                    icoRes = New DrawingBrush(childDes.Icon.Drawing)
                End If
                If icoRes Is Nothing Then Continue For
                If Not ToolboxIconExtraction.iconsDict.Contains(resourceKey) Then ToolboxIconExtraction.iconsDict.Add(resourceKey, icoRes)
            Next

            'Activity からアイコンを抽出する
            actDes = childAsm.GetTypes().Where(Function(t)
                                                   Return (GetType(Activity).IsAssignableFrom(t) OrElse
                                                              GetType(IActivityTemplateFactory).IsAssignableFrom(t)) AndAlso
                                                       Not t.IsAbstract AndAlso t.IsVisible
                                               End Function)
            For Each childAct In actDes
                Dim targetActivityName = childAct.Name
                If (targetActivityName.Contains("Designer")) Then targetActivityName = targetActivityName.Replace("Designer", "")
                Dim resourceKey = ToolboxIconExtraction.GetResourceName(targetActivityName)
                If ToolboxIconExtraction.iconsDict.Contains(resourceKey) Then Continue For

                Dim ch = TypeDescriptor.GetAttributes(childAct).OfType(Of System.Drawing.ToolboxBitmapAttribute)().FirstOrDefault
                If ch Is Nothing Then Continue For

                Dim icoRes As DrawingBrush = Nothing
                Dim img = ch.GetImage(childAct)
                If img Is Nothing Then Continue For
                Dim iconImg = TryCast(img, System.Drawing.Bitmap)
                iconImg.MakeTransparent()

                Dim ms As New MemoryStream
                img.Save(ms, System.Drawing.Imaging.ImageFormat.Png)
                ms.Seek(0, SeekOrigin.Begin)
                Dim bimg As New BitmapImage
                bimg.BeginInit()
                bimg.StreamSource = New MemoryStream(ms.ToArray)
                bimg.EndInit()
                icoRes = New DrawingBrush(New ImageDrawing With {
                                          .ImageSource = bimg,
                                          .Rect = New Rect(0, 0, img.Size.Width, img.Size.Height)})
                ToolboxIconExtraction.iconsDict.Add(resourceKey, icoRes)
            Next
        Next

        Return resultAsms
    End Function

    ''' <summary>指定したクラスを継承しているかをチェック</summary>
    Private Function CheckBaseClass(ByVal targetType As Type, ByVal checkType As Type) As Boolean
        If checkType.IsInterface Then
            If targetType.GetInterfaces.Where(Function(t)
                                                  Return t = checkType
                                              End Function) IsNot Nothing Then
                Return True
            End If
            Return False
        End If

        If targetType Is checkType Then Return True
        Dim base = targetType.BaseType
        If base Is Nothing Then Return False
        If base Is checkType Then Return True
        Return CheckBaseClass(base, checkType)
    End Function

    ''' <summary>Statemachine 関係のアクティビティかどうか</summary>
    Private Function IsStatemachineActivity(ByVal targetType As Type) As Boolean
        Return targetType.FullName.Equals("System.Activities.Core.Presentation.Factories.StateMachineWithInitialStateFactory") OrElse
                            targetType.FullName.Equals("System.Activities.Statements.State") OrElse
                            targetType.FullName.Equals("System.Activities.Core.Presentation.FinalState") OrElse
                            targetType.FullName.Equals("Microsoft.Activities.Statements.Design.ToolboxItems.StateMachineWithInitialStateFactory") OrElse
                            targetType.FullName.Equals("Microsoft.Activities.Statements.State") OrElse
                            targetType.FullName.Equals("Microsoft.Activities.Statements.Design.ToolboxItems.FinalState")
    End Function

    Private Sub CheckPluginLibrary(ByVal pluginFolder As String)
        _pluginList.Plugins.Clear()
        For Each subFld In IO.Directory.GetDirectories(pluginFolder, "*", SearchOption.TopDirectoryOnly)
            For Each childLib In IO.Directory.GetFiles(subFld, "*.dll")
                Dim targetAsm = Reflection.Assembly.LoadFrom(childLib)

                For Each child In targetAsm.GetTypes().Where(Function(t)
                                                                 Return (IsStatemachineActivity(t) OrElse
                                                                            GetType(Activity).IsAssignableFrom(t) OrElse
                                                                            GetType(IActivityTemplateFactory).IsAssignableFrom(t)) AndAlso
                                                                     Not t.IsAbstract AndAlso t.IsVisible
                                                             End Function)
                    Dim childActivity As New PluginLibraryEntity With {
                        .PluginFolder = subFld,
                        .LibraryFile = IO.Path.GetFileNameWithoutExtension(childLib),
                        .IsLoad = False,
                        .CategoryName = IO.Path.GetFileNameWithoutExtension(childLib)}
                    Dim activityName = child.Name
                    If activityName.Contains("`") Then
                        activityName = activityName.Substring(0, activityName.LastIndexOf("`"))
                    End If
                    childActivity.ActivityName = activityName
                    If _pluginList.Plugins.Where(Function(ent)
                                                     Return ent.ActivityName = activityName
                                                 End Function).Count <= 0 Then
                        _pluginList.Plugins.Add(childActivity)
                    End If
                Next

            Next
        Next
    End Sub


    Private Sub ShowLibrarySettingDialogs()
        Dim dlg As New InitialLoadSettingDialog With {.PluginsList = _pluginList}
        If dlg.ShowDialog Then

        End If
    End Sub

#End Region

#Region "その他 Other"

    ''' <summary>リソースより文字列の取得</summary>
    Private Function GetResourceStrings(ByVal resourceName As String, ByVal defaultStrings As String)
        Dim locMes = CStr(Application.Current.TryFindResource(resourceName))
        If (locMes Is Nothing) OrElse (locMes.Trim = "") Then locMes = defaultStrings
        Return locMes
    End Function

    ''' <summary>起動時に読み込むプラグインの設定保存</summary>
    ''' <remarks>Save plugin settings, application loaded</remarks>
    Private Sub SaveLibrarySettings()
        Dim entityType = {GetType(PluginLibraryEntity)}
        Dim serializer As New Runtime.Serialization.DataContractSerializer(GetType(PluginList), entityType)
        Using fs As New FileStream(_pluginListFilename, FileMode.Create)
            serializer.WriteObject(fs, _pluginList)
        End Using
    End Sub

    ''' <summary>起動時に読み込むプラグインの設定取得</summary>
    ''' <remarks>Load plugin settings, application loaded</remarks>
    Private Sub LoadLibrarySettings()
        If Not IO.File.Exists(_pluginListFilename) Then Return
        Dim entityType = {GetType(PluginLibraryEntity)}
        Dim serializer As New Runtime.Serialization.DataContractSerializer(GetType(PluginList), entityType)
        Using fs As New FileStream(_pluginListFilename, FileMode.Open)
            Dim loadValue = TryCast(serializer.ReadObject(fs), PluginList)
            If loadValue Is Nothing Then Return
            _pluginList = loadValue
        End Using
    End Sub

#End Region

#Region "IIS Express"

    Private Const REGPATH_X86 = "SOFTWARE\Microsoft\IISExpress"
    Private Const REGPATH_X64 = "SOFTWARE\Wow6432Node\Microsoft\IISExpress"
    Private Const REG_IISVERSION = "7.5"
    Private Const REG_INSTALLPATH = "InstallPath"
    Private _executingIISExpress As Boolean = False

    ' <summary>IIS Express がインストールされているか</summary>
    'Public Shared ReadOnly IsInstalledIISExpressProperty As DependencyProperty =
    '    DependencyProperty.Register("IsInstalledIISExpress", GetType(Boolean), GetType(MainWindow))
    'Public ReadOnly Property IsInstalledIISExpress As Boolean
    '    Get
    '        Return IsIISExpressInstalled()
    '    End Get
    'End Property

    ''' <summary>IIS Express がインストールされているかをチェック</summary>
    Private Function IsIISExpressInstalled() As Boolean

        Dim result = False
        Try
            Dim key As Microsoft.Win32.RegistryKey = Nothing
            If Environment.Is64BitOperatingSystem Then
                key = My.Computer.Registry.LocalMachine.OpenSubKey(REGPATH_X64, False)
            Else
                key = My.Computer.Registry.LocalMachine.OpenSubKey(REGPATH_X86, False)
            End If
            If key IsNot Nothing Then result = True

        Catch ex As Exception

        End Try
        Return result
    End Function

    ''' <summary>IIS Express のインストールフォルダを取得</summary>
    Private Function GetIISExpressFolder() As String
        Dim result = ""
        Try
            Dim key As Microsoft.Win32.RegistryKey = Nothing
            If Environment.Is64BitOperatingSystem Then
                key = My.Computer.Registry.LocalMachine.OpenSubKey(REGPATH_X64, False)
            Else
                key = My.Computer.Registry.LocalMachine.OpenSubKey(REGPATH_X86, False)
            End If
            If key Is Nothing Then Exit Try

            Dim verKey = key.OpenSubKey(REG_IISVERSION, False)
            If verKey Is Nothing Then Exit Try

            Dim insPathKey = verKey.GetValue(REG_INSTALLPATH)
            If insPathKey Is Nothing Then Exit Try

            result = insPathKey.ToString
        Catch ex As Exception

        End Try
        Return result
    End Function

#End Region

#Region "インテリセンス Intellisense"
    Private _inttelisenseList As New TreeNodes

    Private Sub CreateIntellisenseList()
        Dim wfAsm = Reflection.Assembly.GetExecutingAssembly
        Dim refAsmList = (From x In wfAsm.GetReferencedAssemblies
                                  Select Reflection.Assembly.Load(x)).ToList
        Dim typeList = refAsmList.SelectMany(Function(a) (From x In a.GetTypes
                                                                      Where x.IsPublic AndAlso x.IsVisible AndAlso
                                                                                ((x.Namespace IsNot Nothing) AndAlso
                                                                                 (Not x.Namespace.Contains(My.Application.Info.CompanyName)))
                                                                      Select x)).ToList
        '名前空間・クラス等の抽出
        _inttelisenseList.Nodes.Clear()
        For Each asmType In typeList
            Dim childAsm = asmType
            Me.AddNode(_inttelisenseList, childAsm.Namespace)
            Me.AddTypeNode(_inttelisenseList, childAsm)
        Next
        'キーワードを追加
        Me.AddNode(_inttelisenseList, "New", False)

        Me.SortNodes(_inttelisenseList)
    End Sub

#Region "インテリセンスノード作成: Create Intellisense Node Data"
    Private Overloads Sub AddNode(ByVal targetNodes As TreeNodes, ByVal namePath As String)
        Dim targetPath = namePath.Split(".")
        Dim validPath As Boolean = False
        Dim existsNodes As TreeNodes = Nothing

        Dim validNode = From x In targetNodes.Nodes
                                Where x.Name.ToLower = targetPath(0).ToLower
                                Select x

        If (validNode IsNot Nothing) AndAlso (validNode.Count > 0) Then
            existsNodes = validNode.FirstOrDefault
            validPath = True
        End If

        If Not validPath Then
            Dim childNodes As New TreeNodes With {
                .Name = targetPath(0),
                .AddStrings = targetPath(0),
                .ItemType = TreeNodes.NodeTypes.Namespace,
                .Parent = targetNodes,
                .Description = String.Format("Namespace {0}", targetPath(0))
            }
            targetNodes.AddNode(childNodes)

            Dim nextPath = namePath.Substring(targetPath(0).Length, namePath.Length - targetPath(0).Length)
            If nextPath.StartsWith(".") Then nextPath = nextPath.Substring(1, nextPath.Length - 1)
            If nextPath.Trim <> "" Then Me.AddNode(childNodes, nextPath)
        Else
            Dim nextPath = namePath.Substring(targetPath(0).Length, namePath.Length - targetPath(0).Length)
            If nextPath.StartsWith(".") Then nextPath = nextPath.Substring(1, nextPath.Length - 1)
            If nextPath.Trim <> "" Then Me.AddNode(existsNodes, nextPath)
        End If
    End Sub
    Private Overloads Sub AddNode(ByVal targetNodes As TreeNodes, ByVal namePath As String, ByVal isNamespace As Boolean)
        Dim targetPath = namePath.Split(".")
        Dim validPath As Boolean = False
        Dim existsNodes As TreeNodes = Nothing

        Dim validNode = From x In targetNodes.Nodes
                                Where x.Name.ToLower = targetPath(0).ToLower
                                Select x

        If (validNode IsNot Nothing) AndAlso (validNode.Count > 0) Then
            existsNodes = validNode.FirstOrDefault
            validPath = True
        End If

        If Not validPath Then
            Dim childNodes As New TreeNodes With {
                .Name = targetPath(0),
                .AddStrings = targetPath(0),
                .ItemType = If(isNamespace, TreeNodes.NodeTypes.Namespace, TreeNodes.NodeTypes.Primitive),
                .Parent = targetNodes,
                .Description = If(isNamespace, String.Format("Namespace {0}", targetPath(0)), "")
            }
            targetNodes.AddNode(childNodes)

            If isNamespace Then
                Dim nextPath = namePath.Substring(targetPath(0).Length, namePath.Length - targetPath(0).Length)
                If nextPath.StartsWith(".") Then nextPath = nextPath.Substring(1, nextPath.Length - 1)
                If nextPath.Trim <> "" Then Me.AddNode(childNodes, nextPath)
            End If
        Else
            If isNamespace Then
                Dim nextPath = namePath.Substring(targetPath(0).Length, namePath.Length - targetPath(0).Length)
                If nextPath.StartsWith(".") Then nextPath = nextPath.Substring(1, nextPath.Length - 1)
                If nextPath.Trim <> "" Then Me.AddNode(existsNodes, nextPath)
            End If
        End If
    End Sub

    Private Sub AddTypeNode(ByVal targetNodes As TreeNodes, ByVal target As Type)
        If target.IsAbstract OrElse Not target.IsVisible Then Return

        Dim typeNamespace = target.Namespace
        Dim typeName = target.Name

        Dim parentNode = Me.SearchNodes(targetNodes, typeNamespace)
        Dim newNodes As New TreeNodes With {
            .Name = typeName,
            .AddStrings = typeName,
            .Parent = parentNode,
            .SystemType = target
        }
        Dim nodesName As String = typeName
        Select Case True
            Case target.IsGenericType : newNodes.ItemType = TreeNodes.NodeTypes.Class
                'ジェネリック時 Case Generic
                If typeName.Contains("`") Then
                    nodesName = typeName.Substring(0, typeName.LastIndexOf("`"))
                    newNodes.AddStrings = nodesName
                End If
                Dim paramStrings As New System.Text.StringBuilder
                Dim count As Integer = 0
                For Each childArg In target.GetGenericArguments
                    If count > 0 Then paramStrings.Append(", ")
                    paramStrings.Append(childArg.Name)
                    count += 1
                Next
                nodesName += "(" + paramStrings.ToString + ")"
                newNodes.Name = nodesName
                newNodes.Description = String.Format("Class {0}", newNodes.AddStrings)
            Case target.IsClass : newNodes.ItemType = TreeNodes.NodeTypes.Class
                newNodes.Description = String.Format("Class {0}", newNodes.AddStrings)
            Case target.IsEnum : newNodes.ItemType = TreeNodes.NodeTypes.Enum
                newNodes.Description = String.Format("Enum {0}", newNodes.AddStrings)
            Case target.IsInterface : newNodes.ItemType = TreeNodes.NodeTypes.Interface
                newNodes.Description = String.Format("Interface {0}", newNodes.AddStrings)
            Case target.IsPrimitive : newNodes.ItemType = TreeNodes.NodeTypes.Primitive
                newNodes.Description = String.Format("{0}", newNodes.AddStrings)
            Case target.IsValueType : newNodes.ItemType = TreeNodes.NodeTypes.ValueType
                newNodes.Description = String.Format("{0}", newNodes.AddStrings)
            Case Else : Return
        End Select
        If parentNode Is Nothing Then
            targetNodes.AddNode(newNodes)
        Else
            parentNode.AddNode(newNodes)
        End If
        '対象のメソッド・プロパティ・フィールドを抽出
        Me.AddMethodNode(newNodes, target)
        Me.AddPropertyNode(newNodes, target)
        Me.AddFieldNode(newNodes, target)
        Me.AddEventNode(newNodes, target)
        Me.AddNestedTypeNode(newNodes, target)
    End Sub

    Private Sub AddMethodNode(ByVal targetNodes As TreeNodes, ByVal target As Type)
        Tasks.Parallel.ForEach(target.GetMethods(BindingFlags.Public Or BindingFlags.Static Or
                                                               BindingFlags.Instance), Sub(targetmember)
                                                                                           Dim memberNodes As New TreeNodes With {
                                                                                               .Name = targetmember.Name,
                                                                                               .AddStrings = targetmember.Name,
                                                                                               .ItemType = TreeNodes.NodeTypes.Method,
                                                                                               .Parent = targetNodes,
                                                                                               .Description = CreateMethodDescription(targetmember)
                                                                                           }

                                                                                           targetNodes.AddNode(memberNodes)
                                                                                       End Sub)
    End Sub

    Private Sub AddPropertyNode(ByVal targetNodes As TreeNodes, ByVal target As Type)
        Tasks.Parallel.ForEach(target.GetProperties(BindingFlags.Public Or BindingFlags.Static Or
                                                               BindingFlags.Instance), Sub(targetmember)
                                                                                           Dim memberNodes As New TreeNodes With {
                                                                                               .Name = targetmember.Name,
                                                                                               .AddStrings = targetmember.Name,
                                                                                               .ItemType = TreeNodes.NodeTypes.Property,
                                                                                               .Parent = targetNodes,
                                                                                               .Description = CreatePropertyDescription(targetmember)
                                                                                           }

                                                                                           targetNodes.AddNode(memberNodes)
                                                                                       End Sub)
    End Sub

    Private Sub AddFieldNode(ByVal targetNodes As TreeNodes, ByVal target As Type)
        Tasks.Parallel.ForEach(target.GetFields(BindingFlags.Public Or BindingFlags.Static Or
                                                               BindingFlags.Instance), Sub(targetmember)
                                                                                           Dim memberNodes As New TreeNodes With {
                                                                                               .Name = targetmember.Name,
                                                                                               .AddStrings = targetmember.Name,
                                                                                               .ItemType = TreeNodes.NodeTypes.Field,
                                                                                               .Parent = targetNodes,
                                                                                               .Description = CreateFieldDescription(targetmember)
                                                                                           }

                                                                                           targetNodes.AddNode(memberNodes)
                                                                                       End Sub)
    End Sub

    Private Sub AddEventNode(ByVal targetNodes As TreeNodes, ByVal target As Type)
        Tasks.Parallel.ForEach(target.GetEvents(BindingFlags.Public Or BindingFlags.Static Or
                                                                         BindingFlags.Instance), Sub(targetmember)
                                                                                                     Dim memberNodes As New TreeNodes With {
                                                                                                         .Name = targetmember.Name,
                                                                                                         .AddStrings = targetmember.Name,
                                                                                                         .ItemType = TreeNodes.NodeTypes.Event,
                                                                                                         .Parent = targetNodes,
                                                                                                         .Description = CreateEventDescription(targetmember)
                                                                                                     }

                                                                                                     targetNodes.AddNode(memberNodes)
                                                                                                 End Sub)
    End Sub

    Private Sub AddNestedTypeNode(ByVal targetNodes As TreeNodes, ByVal target As Type)
        Tasks.Parallel.ForEach(target.GetNestedTypes(BindingFlags.Public Or BindingFlags.Static Or
                                                                         BindingFlags.Instance), Sub(targetmember)
                                                                                                     Dim memberNodes As New TreeNodes With {
                                                                                                         .Name = targetmember.Name,
                                                                                                         .AddStrings = targetmember.Name,
                                                                                                         .ItemType = TreeNodes.NodeTypes.Method,
                                                                                                         .Parent = targetNodes
                                                                                                     }

                                                                                                     targetNodes.AddNode(memberNodes)
                                                                                                 End Sub)
    End Sub
#End Region

    Private Function SearchNodes(ByVal targetNodes As TreeNodes, ByVal namePath As String) As TreeNodes
        Dim targetPath = namePath.Split(".")
        Dim validPath As Boolean = False
        Dim existsNodes As TreeNodes = Nothing

        Dim validNode = From x In targetNodes.Nodes
                                    Where x.Name.ToLower = targetPath(0).ToLower
                                    Select x

        If (validNode IsNot Nothing) AndAlso (validNode.Count > 0) Then
            existsNodes = validNode.FirstOrDefault
            validPath = True
        End If

        If Not validPath Then Return targetNodes

        Dim nextPath = namePath.Substring(targetPath(0).Length, namePath.Length - targetPath(0).Length)
        If nextPath.StartsWith(".") Then nextPath = nextPath.Substring(1, nextPath.Length - 1)
        If nextPath.Trim = "" Then Return existsNodes
        Return Me.SearchNodes(existsNodes, nextPath)
    End Function

    Private Sub SortNodes(ByVal targetNodes As TreeNodes)
        targetNodes.Nodes.Sort(New ComparerName)
        For Each childNode In targetNodes.Nodes
            Me.SortNodes(childNode)
        Next
    End Sub

#Region "ツールヒント作成: Create Tooltips"

    Private Function CreateMethodDescription(ByVal target As MethodInfo) As String
        Dim desc As New Text.StringBuilder
        If target.IsPublic Then desc.Append("Public ")
        If target.IsFamily Then desc.Append("Protected ")
        If target.IsAssembly Then desc.Append("Friend ")
        If target.IsPrivate Then desc.Append("Private ")
        If target.IsAbstract Then desc.Append("MustOverride ")
        If target.IsVirtual AndAlso Not target.IsFinal Then desc.Append("Overridable ")
        If target.IsStatic Then desc.Append("Shared ")

        If (Not target.ReturnType Is GetType(Void)) Then
            desc.Append("Function ")
        Else
            desc.Append("Sub ")
        End If

        desc.Append(target.Name)
        desc.Append(CreateGenericParameter(target))

        desc.Append("(")
        Dim paramIndex As Integer = 0
        For Each param In target.GetParameters
            If paramIndex > 0 Then desc.Append(", ")
            If param.IsOptional Then desc.Append("Optional ")
            If param.IsOut Then
                desc.Append("ByRef ")
            Else
                desc.Append("ByVal ")
            End If
            desc.Append(param.Name + " As " + param.ParameterType.Name)
            desc.Append(CreateGenericParameter(param.ParameterType))
            If Not IsDBNull(param.DefaultValue) Then
                If param.DefaultValue Is Nothing Then
                    desc.Append(" = Nothing")
                Else
                    desc.Append(" = " + param.DefaultValue.ToString)
                End If
            End If
            paramIndex += 1
        Next
        desc.Append(") ")
        If target.ReturnType IsNot Nothing Then
            desc.Append("As " + target.ReturnType.Name)
            desc.Append(CreateGenericParameter(target.ReturnType))
        End If
        Return desc.ToString
    End Function

    Private Function CreatePropertyDescription(ByVal target As PropertyInfo) As String
        Dim desc As New Text.StringBuilder

        If target.CanRead AndAlso target.CanWrite Then
        ElseIf target.CanRead Then
            desc.Append("ReadOnly ")
        Else
            desc.Append("WriteOnly ")
        End If
        desc.Append("Property " + target.Name + " As " + target.PropertyType.Name)
        desc.Append(CreateGenericParameter(target.PropertyType))

        Return desc.ToString
    End Function

    Private Function CreateFieldDescription(ByVal target As FieldInfo) As String
        Dim desc As New Text.StringBuilder
        If target.IsPublic Then desc.Append("Public ")
        If target.IsPrivate Then desc.Append("Private ")
        If target.IsStatic Then desc.Append("Shared ")

        desc.Append(target.Name)
        desc.Append("() ")
        If target.FieldType IsNot Nothing Then
            desc.Append("As " + target.FieldType.Name)
            desc.Append(CreateGenericParameter(target.FieldType))
        End If
        Return desc.ToString
    End Function

    Private Function CreateEventDescription(ByVal target As EventInfo) As String
        Dim desc As New Text.StringBuilder

        desc.Append(target.Name)
        If target.EventHandlerType IsNot Nothing Then
            desc.Append("As " + target.EventHandlerType.Name)
            If target.EventHandlerType.IsGenericType Then
                desc.Append(CreateGenericParameter(target.EventHandlerType))
            End If
        End If
        Return desc.ToString
    End Function

    Private Overloads Function CreateGenericParameter(ByVal target As MethodInfo) As String
        Dim result As New Text.StringBuilder
        If target.IsGenericMethod Then
            result.Append("(Of ")
            Dim genIndex As Integer = 0
            For Each genParam In target.GetGenericArguments
                If genIndex > 0 Then result.Append(", ")
                result.Append(genParam.Name)
                genIndex += 1
            Next
            result.Append(")")
        End If
        Return result.ToString
    End Function
    Private Overloads Function CreateGenericParameter(ByVal target As Type) As String
        Dim result As New Text.StringBuilder
        If target.IsGenericType Then
            result.Append("(Of ")
            Dim genIndex As Integer = 0
            For Each genParam In target.GetGenericArguments
                If genIndex > 0 Then result.Append(", ")
                result.Append(genParam.Name)
                genIndex += 1
            Next
            result.Append(")")
        End If
        Return result.ToString
    End Function

#End Region

#Region "ハイライト Syntax Highlight"
    Private Function CreateKeywords() As String
        Dim words As New Text.StringBuilder
        With words
            .Append("AddHandler|")
            .Append("AddressOf|")
            .Append("Alias|")
            .Append("And|")
            .Append("AndAlso|")
            .Append("As|")
            .Append("Boolean|")
            .Append("ByRef|")
            .Append("Byte|")
            .Append("ByVal|")
            .Append("Call|")
            .Append("Case|")
            .Append("Catch|")
            .Append("CBool|")
            .Append("CByte|")
            .Append("CChar|")
            .Append("CDate|")
            .Append("CDbl|")
            .Append("CDec|")
            .Append("Char|")
            .Append("CInt|")
            .Append("Class|")
            .Append("CLng|")
            .Append("CObj|")
            .Append("Const|")
            .Append("Continue|")
            .Append("CSByte|")
            .Append("CShort|")
            .Append("CSng|")
            .Append("CStr|")
            .Append("CType|")
            .Append("CUInt|")
            .Append("CULng|")
            .Append("CUShort|")
            .Append("Date|")
            .Append("Decimal|")
            .Append("Declare|")
            .Append("Default|")
            .Append("Delegate|")
            .Append("Dim|")
            .Append("DirectCast|")
            .Append("Do|")
            .Append("Double|")
            .Append("Each|")
            .Append("Else|")
            .Append("ElseIf|")
            .Append("End|")
            .Append("EndIf|")
            .Append("Enum|")
            .Append("Erase|")
            .Append("Error|")
            .Append("Event|")
            .Append("Exit|")
            .Append("False|")
            .Append("Finally|")
            .Append("For|")
            .Append("Friend|")
            .Append("Function|")
            .Append("Get|")
            .Append("GetType|")
            .Append("GetXMLNamespace|")
            .Append("Global|")
            .Append("GoSub|")
            .Append("GoTo|")
            .Append("Handles|")
            .Append("If|")
            .Append("Implements|")
            .Append("Imports|")
            .Append("In|")
            .Append("Inherits|")
            .Append("Integer|")
            .Append("Interface|")
            .Append("Is|")
            .Append("IsNot|")
            .Append("Let|")
            .Append("Lib|")
            .Append("Like|")
            .Append("Long|")
            .Append("Loop|")
            .Append("Me|")
            .Append("Mod|")
            .Append("Module|")
            .Append("MustInherit|")
            .Append("MustOverride|")
            .Append("MyBase|")
            .Append("MyClass|")
            .Append("Namespace|")
            .Append("Narrowing|")
            .Append("New|")
            .Append("Next|")
            .Append("Not|")
            .Append("Nothing|")
            .Append("NotInheritable|")
            .Append("NotOverridable|")
            .Append("Object|")
            .Append("Of|")
            .Append("On|")
            .Append("Operator|")
            .Append("Option|")
            .Append("Optional|")
            .Append("Or|")
            .Append("OrElse|")
            .Append("Out|")
            .Append("Overloads|")
            .Append("Overridable|")
            .Append("Overrides|")
            .Append("ParamArray|")
            .Append("Partial|")
            .Append("Private|")
            .Append("Property|")
            .Append("Protected|")
            .Append("Public|")
            .Append("RaiseEvent|")
            .Append("ReadOnly|")
            .Append("ReDim|")
            .Append("REM|")
            .Append("RemoveHandler|")
            .Append("Resume|")
            .Append("Return|")
            .Append("SByte|")
            .Append("Select|")
            .Append("Set|")
            .Append("Shadows|")
            .Append("Shared|")
            .Append("Short|")
            .Append("Single|")
            .Append("Static|")
            .Append("Step|")
            .Append("Stop|")
            .Append("String|")
            .Append("Structure|")
            .Append("Sub|")
            .Append("SyncLock|")
            .Append("Then|")
            .Append("Throw|")
            .Append("To|")
            .Append("True|")
            .Append("Try|")
            .Append("TryCast|")
            .Append("TypeOf|")
            .Append("UInteger|")
            .Append("ULong|")
            .Append("UShort|")
            .Append("Using|")
            .Append("Variant|")
            .Append("Wend|")
            .Append("While|")
            .Append("Widening|")
            .Append("With|")
            .Append("WithEvents|")
            .Append("WriteOnly|")
            .Append("Xor|")
            .Append("#Const|")
            .Append("#Else|")
            .Append("#ElseIf|")
            .Append("#End|")
            .Append("#If")
        End With
        Return words.ToString
    End Function
#End Region

#End Region

#Region "コマンドラインオプション Command Line Option"
    ''' <summary>コマンドラインオプションの統一</summary>
    Private Function ReplaceArguments(ByVal args As String()) As String()
        Dim resultArgs As String() = args
        For index = 0 To args.Length - 1
            Dim childArgs = args(index)
            If Not childArgs.StartsWith("-") Then Continue For

            childArgs = "/" & childArgs.Substring(1)
            If childArgs.Substring(1, 5).ToLower = WFFILE_ARGS Then
                childArgs = childArgs.Substring(0, 1) + WFFILE_ARGS + childArgs.Substring(6)
            End If
            resultArgs(index) = childArgs
        Next

        Return resultArgs
    End Function

    ''' <summary>コマンドライン引数からのワークフローファイル名取得</summary>
    Private Function GetWorkflowFilename(ByVal args As String()) As String
        Dim result = ""
        Dim argValue = "/" + WFFILE_ARGS + ":"
        Dim r = From x In args
                Where x.StartsWith(argValue)
                Select x.Replace(argValue, "")

        If (r IsNot Nothing) AndAlso (r.Count > 0) AndAlso (r.First <> "") Then result = r.First
        Return result
    End Function

    ''' <summary>コマンドライン引数からのプラグインフォルダ取得</summary>
    Private Function GetPlugiinFolderOption(ByVal args As String()) As String
        Dim result = ""
        Dim argValue = "/" + WFPLUGIN_ARGS + ":"
        Dim r = From x In args
                Where x.StartsWith(argValue)
                Select x.Replace(argValue, "")

        If (r IsNot Nothing) AndAlso (r.Count > 0) AndAlso (r.First <> "") Then result = r.First
        Return result
    End Function

    ''' <summary>コマンドライン引数からの初期ワークフロー取得</summary>
    Private Function GetInitializeOption(ByVal args As String()) As String
        Dim result = ""
        Dim argValue = "/" + WFINITIAL_ARGS + ":"
        Dim r = From x In args
                Where x.StartsWith(argValue)
                Select x.Replace(argValue, "")

        If (r IsNot Nothing) AndAlso (r.Count > 0) AndAlso (r.First <> "") Then result = r.First
        Return result
    End Function

    ''' <summary>コマンドライン引数をワークフロー種別に変換</summary>
    Private Function ConvertArgumentToWorkflowType(ByVal args As String) As enmCreateType
        Dim wfType As enmCreateType = enmCreateType.Sequential
        Select Case args.ToUpper
            Case "SEQUENTIAL", "SQ"
                wfType = enmCreateType.Sequential
            Case "FLOWCHART", "FC"
                wfType = enmCreateType.Flowchart
            Case "STATEMACHINE", "SM"
                If CanUseStatemachine() Then wfType = enmCreateType.Statemachine
            Case "WORKFLOWSERVICE", "WS"
                wfType = enmCreateType.WorkflowService
            Case Else
        End Select
        Return wfType
    End Function

#End Region

#Region "デザイナのコンテキストメニュー WorkflowDesigner's ContextMenu"
    ''' <summary>コンテキストメニューの追加</summary>
    Private Sub AddContextMenu()
        Dim dvSvc = designer.Context.Services.GetService(Of DesignerView)()
        If dvSvc Is Nothing Then Return
        Dim dv = dvSvc.ContextMenu
        If dv Is Nothing Then Return

        'Dim importContextMenu As New MenuItem With {
        '    .Header = GetResourceStrings("CMImportWorkflow", "ワークフローのインポート")
        '}
        'AddHandler importContextMenu.Click, AddressOf ImportWorkflow

        Dim buildContextMenu As New MenuItem With {
            .Header = GetResourceStrings("CMBuildWorkflow", "ワークフローのビルド"),
            .IsEnabled = CanUseMSBuild()
        }
        AddHandler buildContextMenu.Click, AddressOf BuildWorkflow

        'dv.Items.Add(importContextMenu)
        dv.Items.Add(buildContextMenu)
    End Sub

    ''' <summary>ワークフローのインポート</summary>
    Private Sub ImportWorkflow(ByVal sender As Object, ByVal e As EventArgs)

        Dim mds = designer.Context.Services.GetService(Of ModelService)()
        If mds Is Nothing Then Return

        Dim actCollection = mds.Find(mds.Root, GetType(Activity))
        Dim targetActivity = actCollection.FirstOrDefault
        Do While (targetActivity.Parent IsNot Nothing) AndAlso
                      (targetActivity.Parent.ItemType = GetType(Sequence))
            targetActivity = targetActivity.Parent
        Loop

        'ワークフローの読み込み
        Dim dlg As New Microsoft.Win32.OpenFileDialog
        With dlg
            .AddExtension = True
            .CheckFileExists = True
            .Filter = Me.GetResourceStrings("MsgOpenWorkflowFilter",
                                            "ワークフロー(*.xaml)|*.xaml|ワークフローサービス(*.xamlx) |*.xamlx|全てのファイル(*.*)|*.*")
        End With
        If Not dlg.ShowDialog Then Return

        Dim otherActivity = ActivityXamlServices.Load(dlg.FileName)
        otherActivity.DisplayName = IO.Path.GetFileName(dlg.FileName)
        Try
            Using editScope = targetActivity.BeginEdit("Activities")
                targetActivity.Properties("Activities").Collection.Add(otherActivity)
                editScope.Complete()
            End Using
        Catch ex As Exception

        End Try

    End Sub

    ''' <summary>ワークフローのビルド</summary>
    Private Sub BuildWorkflow(ByVal sender As Object, ByVal e As EventArgs)
        Me.CreateActivityLibrary()
    End Sub

#End Region

#Region "アクティビティライブラリ作成 Create Activity Dll"

    ''' <summary>アクティビティ DLL の作成</summary>
    Private Sub CreateActivityLibrary()

        Dim errID = Me.ValidateActivities()
        If (errID <> "") OrElse (designer.IsInErrorState) Then
            MessageBox.Show(Me.GetResourceStrings("MsgCheckExceptionInFlow", "ワークフロー中にエラーがあります。"),
                                      My.Application.Info.Title,
                                      MessageBoxButton.OK, MessageBoxImage.Warning)
            If errID <> "" Then
                Dim vsv = designer.Context.Services.GetService(Of ValidationService)()
                vsv.NavigateToError(errID)
            End If
            Return
        End If

        'ワークフローのビルド
        Dim dlg As New Microsoft.Win32.SaveFileDialog
        With dlg
            .AddExtension = True
            .CheckFileExists = False
            .Filter = Me.GetResourceStrings("MsgBuildLibraryFilter",
                                            "リンクライブラリ(*.dll)|*.dll|全てのファイル(*.*)|*.*")
            .FileName = System.IO.Path.GetFileNameWithoutExtension(_editingFilename)
            .InitialDirectory = System.IO.Path.GetDirectoryName(_editingFilename)
        End With

        If Not dlg.ShowDialog Then Return
        Dim wfFile = dlg.FileName

        Me.Cursor = Cursors.Wait
        DispatcherHelper.DoEvents()

        designer.Flush()
        Dim xamlFile = SaveXamlToTemp(designer.Text)

        'バックグラウンドでビルドを実行
        Tasks.Task.Factory.StartNew(Sub()
                                        BuildXAML(xamlFile, wfFile)
                                        Me.Dispatcher.Invoke(DispatcherPriority.Background, Sub()
                                                                                                Me.Cursor = Cursors.Arrow
                                                                                                MessageBox.Show(Me.GetResourceStrings("MsgBuildComplete", "ワークフローのビルドが終了しました。"),
                                                                                                                          My.Application.Info.Title,
                                                                                                                          MessageBoxButton.OK, MessageBoxImage.Information)
                                                                                            End Sub)
                                    End Sub)

    End Sub

    ''' <summary>MSBuild によるアクティビティのビルド</summary>
    Private Sub BuildXAML(ByVal xamlFile As String, ByVal asmFile As String)
        'proj ファイルの生成
        Dim tempProjPath = IO.Path.GetTempFileName
        Dim asmOutPath = IO.Path.GetDirectoryName(asmFile)
        Dim projStrings = CreateProjectFile(xamlFile, asmOutPath, asmFile)

        tempProjPath = IO.Path.Combine(IO.Path.GetDirectoryName(tempProjPath),
                                                       IO.Path.GetFileNameWithoutExtension(tempProjPath) + ".vbproj")

        My.Computer.FileSystem.WriteAllText(tempProjPath, projStrings, False)

        'MSBuild によるビルド
        Dim fwPath = Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory
        Dim buildCommand = IO.Path.Combine(fwPath, "MSBuild.exe")
        Dim prc = Process.Start(buildCommand, tempProjPath)
        prc.WaitForExit()

        Try
            My.Computer.FileSystem.DeleteFile(xamlFile)
            My.Computer.FileSystem.DeleteFile(tempProjPath)
        Catch ex As Exception

        End Try

    End Sub

    ''' <summary>編集中の xaml を一時保存する</summary>
    Private Function SaveXamlToTemp(ByVal xamlString As String) As String
        Dim xamlFileName = IO.Path.GetTempFileName
        xamlFileName = IO.Path.Combine(IO.Path.GetDirectoryName(xamlFileName),
                                                      IO.Path.GetFileNameWithoutExtension(xamlFileName) + ".xaml")
        My.Computer.FileSystem.WriteAllText(xamlFileName, xamlString, False)
        Return xamlFileName
    End Function

    ''' <summary>XAML ビルド用 vbproj ファイルの生成</summary>
    Private Function CreateProjectFile(ByVal xamlFile As String, ByVal outputPath As String, ByVal asmFile As String) As String

        Const XMLNS = "http://schemas.microsoft.com/developer/msbuild/2003"

        Dim xmlPrj As New Xml.XmlDocument
        'Project File Header
        xmlPrj.AppendChild(xmlPrj.CreateXmlDeclaration("1.0", "UTF-8", Nothing))

        Dim rootElem = xmlPrj.CreateElement("Project")
        Dim rootAttrib1 = xmlPrj.CreateAttribute("ToolsVersion")
        rootAttrib1.Value = "4.0"
        Dim rootAttrib2 = xmlPrj.CreateAttribute("DefaultTargets")
        rootAttrib2.Value = "Build"
        Dim rootAttrib3 = xmlPrj.CreateAttribute("xmlns")
        rootAttrib3.Value = XMLNS
        rootElem.Attributes.Append(rootAttrib1)
        rootElem.Attributes.Append(rootAttrib2)
        rootElem.Attributes.Append(rootAttrib3)

        'PropertyGroup
        Dim prpElem = CreateElement(xmlPrj, "PropertyGroup")
        prpElem.AppendChild(CreateElement(xmlPrj, "AssemblyName", IO.Path.GetFileNameWithoutExtension(asmFile)))
        prpElem.AppendChild(CreateElement(xmlPrj, "OutputType", "Library"))
        prpElem.AppendChild(CreateElement(xmlPrj, "OutputPath", outputPath))
        prpElem.AppendChild(CreateElement(xmlPrj, "DebugSymbols", "false"))
        prpElem.AppendChild(CreateElement(xmlPrj, "DebugType", "None"))
        rootElem.AppendChild(prpElem)

        'ItemGroup - Reference
        Dim refItemGroup = CreateElement(xmlPrj, "ItemGroup")
        Dim xamlRefList = Me.AddDefaultReference(Me.GetAssembliesList(xamlFile))
        For Each refAsmName In xamlRefList
            refItemGroup.AppendChild(CreateElement(xmlPrj, "Reference", "Include", refAsmName))
        Next
        rootElem.AppendChild(refItemGroup)

        'ItemGroup - Import
        Dim impItemGroup = CreateElement(xmlPrj, "ItemGroup")
        Dim xamlImpList = Me.AddDefaultImportNamespace(Nothing)
        For Each impName In xamlImpList
            impItemGroup.AppendChild(CreateElement(xmlPrj, "Import", "Include", impName))
        Next
        rootElem.AppendChild(impItemGroup)

        'ItemGroup - XamlAppDef
        Dim xamlItemGroup = CreateElement(xmlPrj, "ItemGroup")
        Dim xamlItemElem = CreateElement(xmlPrj, "XamlAppDef", "Include", xamlFile)
        xamlItemElem.AppendChild(CreateElement(xmlPrj, "SubType", "Designer"))
        xamlItemElem.AppendChild(CreateElement(xmlPrj, "Generator", "MSBuild:Compile"))
        xamlItemGroup.AppendChild(xamlItemElem)

        rootElem.AppendChild(xamlItemGroup)

        'Import
        Dim impElem = CreateElement(xmlPrj, "Import", "Project", "$(MSBuildToolsPath)\Microsoft.VisualBasic.targets")
        rootElem.AppendChild(impElem)

        xmlPrj.AppendChild(rootElem)

        Return xmlPrj.OuterXml
    End Function

    Private Overloads Function CreateElement(ByVal xmlDoc As Xml.XmlDocument, ByVal elementName As String) As Xml.XmlElement
        Dim resultElement = xmlDoc.CreateElement(elementName)
        Return resultElement
    End Function
    Private Overloads Function CreateElement(ByVal xmlDoc As Xml.XmlDocument, ByVal elementName As String, ByVal elementValue As String) As Xml.XmlElement
        Dim resultElement = xmlDoc.CreateElement(elementName)
        resultElement.InnerText = elementValue
        Return resultElement
    End Function
    Private Overloads Function CreateElement(ByVal xmlDoc As Xml.XmlDocument, ByVal elementName As String, ByVal attributeName As String, ByVal attributeValue As String) As Xml.XmlElement
        Dim resultElement = xmlDoc.CreateElement(elementName)
        Dim appendAttribute = xmlDoc.CreateAttribute(attributeName)
        appendAttribute.Value = attributeValue
        resultElement.Attributes.Append(appendAttribute)
        Return resultElement
    End Function

    ''' <summary>XAML 上で参照されているアセンブリ一覧を取得</summary>
    Private Function GetAssembliesList(ByVal xamlString As String) As List(Of String)
        Dim xDoc = XDocument.Load(xamlString)
        Dim result = From x In xDoc.Root.Attributes
                          Where x.Value.Contains("clr-namespace")
                          Select x.Value.Split("=")(1)

        Return result.ToList
    End Function

    ''' <summary>アクティビティのビルドに最低限必要な参照設定を追加する</summary>
    Private Function AddDefaultReference(ByVal refList As List(Of String)) As List(Of String)

        Dim defRefList As New List(Of String)
        defRefList.Add("System")
        defRefList.Add("System.Activities")
        defRefList.Add("System.Core")
        defRefList.Add("System.Data")
        defRefList.Add("System.Runtime.Serialization")
        defRefList.Add("System.ServiceModel")
        defRefList.Add("System.Xaml")
        defRefList.Add("System.Xml")
        defRefList.Add("System.Xml.Linq")

        Return New List(Of String)(refList.Union(defRefList))
    End Function

    ''' <summary>プロジェクトで利用する名前空間のインポートを追加する</summary>
    Private Function AddDefaultImportNamespace(ByVal impList As List(Of String)) As List(Of String)

        Dim defImpList As New List(Of String)
        defImpList.Add("Microsoft.VisualBasic")
        defImpList.Add("System")
        defImpList.Add("System.Collections")
        defImpList.Add("System.Collections.Generic")
        defImpList.Add("System.Data")
        defImpList.Add("System.Diagnostic")
        defImpList.Add("System.Linq")
        defImpList.Add("System.Xml.Linq")
        If impList Is Nothing Then
            Return defImpList
        Else
            Return New List(Of String)(impList.Union(defImpList))
        End If
    End Function

    ''' <summary>MSBuild が利用できるかチェック</summary>
    Private Function CanUseMSBuild() As Boolean
        Dim fwPath = Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory
        Dim buildPrg = IO.Path.Combine(fwPath, "MSBuild.exe")
        Return IO.File.Exists(buildPrg)
    End Function

#End Region

End Class
